/**
 * @author LIU YUAN
 * @date May 15, 2011 11:12:21 AM
 * @param <T>
 */
#include "stdafx.h"
#include "Common.h"
#include <ImageHlp.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <tchar.h>
#include <Shlwapi.h>
#include "InjectUtils.h"
#include "libdasm.h"


#pragma comment(lib, "Imagehlp.lib")
#pragma comment(lib, "Shlwapi.lib")

extern HMODULE module;

typedef enum _MEMORY_INFORMATION_CLASS   
{  
    MemoryBasicInformation,  
    MemoryWorkingSetList,  
    MemorySectionName  
}MEMORY_INFORMATION_CLASS;  
  
typedef  
    NTSTATUS  
    (WINAPI *ZWQUERYVIRTUALMEMORY)  
    (  
    IN HANDLE ProcessHandle,   
    IN PVOID BaseAddress,   
    IN MEMORY_INFORMATION_CLASS MemoryInformationClass,   
    OUT PVOID MemoryInformation,   
    IN ULONG MemoryInformationLength,   
    OUT PULONG ReturnLength OPTIONAL   
    );   
  
BOOL CALLBACK WindowEnumProc(HWND hWnd,LPARAM lParam){
	DWORD dwProcessId;
	char className[MAX_PATH];
	LPWNDINFO pInfo = (LPWNDINFO)lParam;
	GetWindowThreadProcessId(hWnd, &dwProcessId);
	if(pInfo->dwProcessId){
		if(dwProcessId != pInfo->dwProcessId){
			return TRUE;
		}
	}

	if(pInfo->isWindowVisible){
		BOOL isWindowVisible = IsWindowVisible(hWnd);
		if(!isWindowVisible){
			return TRUE;
		}
	}
	
	if(pInfo->className){
		GetClassNameA(hWnd,className,MAX_PATH);
		if(_stricmp(pInfo->className,className)!=0){
			return TRUE;
		}
	}
	
	if(pInfo->isSingleton){
		pInfo->hWnd = hWnd;
		return FALSE;
	}
	pInfo->hWnds[pInfo->hWndsSize++] = hWnd;
	return TRUE;
}


CInjectUtils::CInjectUtils(void)
{
}


CInjectUtils::~CInjectUtils(void)
{
}

void
CInjectUtils::PrintLastErrorMessage(DWORD dw){
	LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        ((lstrlen((LPCTSTR)lpMsgBuf)) + 40) * sizeof(TCHAR)); 

    _stprintf_s((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("The error %d: %s\r\n"), dw, lpMsgBuf);
	_tprintf((LPTSTR)lpDisplayBuf);
	//OutputDebugString((LPTSTR)lpDisplayBuf);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

DWORD
CInjectUtils::GetProcessIdByName(
			LPCWSTR processName)
{

	DWORD processId = 0;

	HANDLE hProcessSnap;
	HANDLE hProcess = NULL;
	PROCESSENTRY32W pe32;
	hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

  if( hProcessSnap == INVALID_HANDLE_VALUE )
  {
    alert("CreateToolhelp32Snapshot (of processes) INVALID_HANDLE_VALUE");
    return processId;
  }
  pe32.dwSize = sizeof( PROCESSENTRY32W );
  
  if( !Process32FirstW( hProcessSnap, &pe32 ) )
  {
    alert("Process32First failed!");
    CloseHandle( hProcessSnap );          // clean the snapshot object
    return processId;
  }

  do
  {
	  if(wcscmp(processName,pe32.szExeFile)==0)
	  {
		  processId = pe32.th32ProcessID;
		  break;
	  }
  }while(Process32NextW( hProcessSnap, &pe32 ));
  CloseHandle( hProcessSnap ); 
  
  if(processId == 0)
  {
	  alert("Found process failed!");
	  return processId;
  }
	return processId;
}

BOOL
CInjectUtils::GetSimpleProcessNameById(DWORD pid,LPSTR lpName,PDWORD cbName){
	HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,pid);
	if(!hProcess){
		return FALSE;
	}

	CHAR lpExeName[MAX_PATH];
	DWORD lpdwsize = MAX_PATH;

	if(QueryFullProcessImageNameA(hProcess,0,lpExeName,&lpdwsize)==0){
		CloseHandle( hProcess );
		return FALSE;
	}

	PSTR pModName = PathFindFileNameA(lpExeName);
	lstrcpyA(lpName,pModName);
	*cbName = lpdwsize;
	CloseHandle( hProcess );
	return TRUE;
}

HMODULE
CInjectUtils::GetModule(
			DWORD processId,
			LPCWSTR moduleName)
{
	MODULE_INFO module_info;
	DWORD cbNeeded = 0;
	CInjectUtils::enumProcessForModule(processId,&module_info,1,&cbNeeded,moduleName);
	if(cbNeeded==0){
		alert("Found module failed!");
		return NULL;
	}
	HMODULE hModule = (HMODULE)module_info.address;
	return hModule;
}

FARPROC 
CInjectUtils::GetFunctionAddr(
            LPCSTR moduleName,
			LPCSTR functionName)
{
	HMODULE hModule = GetModuleHandleA(moduleName);
	if(hModule==NULL)
	{
		CHAR text[100];
		sprintf_s(text,100,"GetProcAddress failed! %d",GetLastError());
		alert(text);
		return NULL;
	}
	FARPROC proc = GetProcAddress(hModule,functionName);
	if(proc==NULL)
	{
		CHAR text[100];
		sprintf_s(text,100,"GetProcAddress failed! %d",GetLastError());
		alert(text);
		return NULL;
	}
	return proc;
}

WCHAR*
CInjectUtils::getWideString(CHAR* str)
{
	DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
	WCHAR *pwText;
    pwText = new WCHAR[dwNum];

	MultiByteToWideChar (CP_ACP, 0, str, -1, pwText, dwNum);
	return pwText;
}

CHAR*
CInjectUtils::getMultiString(WCHAR* str)
{
	DWORD dwNum =WideCharToMultiByte(CP_OEMCP,NULL,str,-1,NULL,0,NULL,FALSE);
	CHAR *pwText;
    pwText = new CHAR[dwNum];

	WideCharToMultiByte (CP_OEMCP,NULL,str,-1,pwText,dwNum,NULL,FALSE);
	return pwText;
}

BOOL
CInjectUtils::getMethodOffsetInDll(
                LPCSTR dllname,
		        LPCSTR method,
				DWORD* offset)
{
	HMODULE dllModule = LoadLibraryA(dllname);
	if(dllModule==NULL)
	{
		return FALSE;
	}

	if(method==NULL||strlen(method)==0)
	{
		FreeLibrary(dllModule);
		return TRUE;
	}
	
	FARPROC proc = ::GetProcAddress(dllModule,method);
	if(proc==NULL)
	{
		FreeLibrary(dllModule);
		return FALSE;
	}
	DWORD dllModuleAddr = (DWORD)dllModule;
	DWORD procAddr = (DWORD)proc;
	*offset = procAddr - dllModuleAddr;
	FreeLibrary(dllModule);
	return TRUE;
}

DWORD
CInjectUtils::getEntryPoint(DWORD processId){
	HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,processId);
	if(!hProcess){
		return NULL;
	}

	DWORD pEntryPoint = 0;
	DWORD imageBase = 0;
	WCHAR processNameW[MAX_PATH*2+4];
	CHAR processNameA[MAX_PATH+2];

	DWORD t = MAX_PATH*2+4;
	if(QueryFullProcessImageNameW(hProcess,0,processNameW,&t)==0){
		CloseHandle( hProcess );
		return 0;
	}
	t = MAX_PATH+2;
	if(QueryFullProcessImageNameA(hProcess,0,processNameA,&t)==0){
		CloseHandle( hProcess );
		return 0;
	}
	
	PIMAGE_NT_HEADERS      pNTHeader;  
    PLOADED_IMAGE       pImage;  
    pImage = ImageLoad(processNameA, NULL);  
    if(pImage == NULL)  {
	   CloseHandle( hProcess );
       return NULL;  
	}
	pNTHeader = pImage->FileHeader;

	PWSTR pModName = PathFindFileNameW(processNameW);
	MODULE_INFO moduleInfo;
	DWORD cbNeeded = 0;
	if(enumProcessForModule(processId,&moduleInfo,1,&cbNeeded,pModName)==0){
        CloseHandle( hProcess );
		return 0;
	}

	if(cbNeeded==0){
		CloseHandle( hProcess );
		return 0;
	}

	imageBase = moduleInfo.address;

	if(imageBase>0){
        pEntryPoint = imageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint;
		ImageUnload(pImage); 
		CloseHandle( hProcess );
		return pEntryPoint;  
	}

	if(pNTHeader->OptionalHeader.DllCharacteristics!=0x8100){
		ImageUnload(pImage);  
		CloseHandle( hProcess );
		return NULL;  
	}
    pEntryPoint = pNTHeader->OptionalHeader.AddressOfEntryPoint + pNTHeader->OptionalHeader.ImageBase;  
    ImageUnload(pImage);  
	CloseHandle( hProcess );
    return pEntryPoint;  
}


BOOL
CInjectUtils::enumProcessForModule(DWORD processId,PMODULE_INFO lpModuleInfo,DWORD cb,LPDWORD lpCbNeeded,LPCWSTR moduleName){
	HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,processId);
	if(!hProcess){
		*lpCbNeeded = 0;
		return FALSE;
	}

	ZWQUERYVIRTUALMEMORY QueryVirtualMemoryFunction=NULL;  
    DWORD Index=0;  
    NTSTATUS NtStatus=0;  
    MEMORY_BASIC_INFORMATION InfoMation;  
    BYTE Buffer[MAX_PATH*2+4]={0};  
    DWORD Counter = 0;  
   
    QueryVirtualMemoryFunction = (ZWQUERYVIRTUALMEMORY)GetFunctionAddr("ntdll.dll","ZwQueryVirtualMemory");  
 
    if (QueryVirtualMemoryFunction==NULL)  
    {  
        *lpCbNeeded = 0;     
    }   
    else   
    {  
        for(Index;Index<0x80000000;Index+=0x1000)  
        {  
			if(Counter>cb){
				break;
			}
            NtStatus=QueryVirtualMemoryFunction  
            (  
            hProcess,  
            (PULONG)Index,  
            MemoryBasicInformation,  
            &InfoMation,  
            sizeof(InfoMation),   
            NULL  
            );  
  
            if (NtStatus>=0)  
            {  
                if (InfoMation.Type==MEM_IMAGE)   
                {  
                    if ((DWORD)InfoMation.AllocationBase==Index)  
                    {   
                        NtStatus=QueryVirtualMemoryFunction  
                            (  
                            (HANDLE)hProcess,   
                            (PULONG)Index,  
                            MemorySectionName,   
                            Buffer,  
                            sizeof(Buffer),  
                            NULL  
                            );  
  
                        if (NtStatus>=0)  
                        {  
							lpModuleInfo[Counter].address = Index;
							PUNICODE_STRING tmp = (PUNICODE_STRING)Buffer;

							if(moduleName){
								PWSTR pModName = PathFindFileNameW(tmp->Buffer);
								if(wcscmp(moduleName,pModName)==0){
									lpModuleInfo[Counter].moduleNameLength = tmp->Length;
									wcscpy_s(lpModuleInfo[Counter].moduleName,lpModuleInfo[Counter].moduleNameLength,tmp->Buffer);
									Counter++;
								}
								continue;
							}

							lpModuleInfo[Counter].moduleNameLength = tmp->Length;
							wcscpy_s(lpModuleInfo[Counter].moduleName,lpModuleInfo[Counter].moduleNameLength,tmp->Buffer);
							Counter++;
                        }  
                    }  
                }  
            }  
        }  
    }
	*lpCbNeeded = Counter;
	CloseHandle(hProcess);
	return TRUE;
}

BOOL
CInjectUtils::injectCodesToProcess(DWORD processId,LPCSTR shellCodes,DWORD nSize){
	HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, processId);
	if(!hProcess){
		return FALSE;
	}



	CloseHandle(hProcess);
	return TRUE;
}

DWORD
CInjectUtils::getOrigCodesSize(DWORD processId,LPCSTR origCodesAddr,DWORD hookCodesSize){
	DWORD origCodesLen = 0;
	INSTRUCTION inst;
	DWORD instLen = 0;
	while(origCodesLen<hookCodesSize){
		instLen = get_instruction(&inst, (BYTE*)origCodesAddr, MODE_32);
		origCodesLen = origCodesLen + instLen;
	}
	return origCodesLen;
}

HWND
CInjectUtils::getSingletonWindow(DWORD processId,HWND parent,LPCSTR className,BOOL isWindowVisible){
	WNDINFO wi;
	wi.dwProcessId = processId;
	wi.hWnd = NULL;
	wi.className = className;
	wi.parent = parent;
	wi.isWindowVisible = isWindowVisible;
	wi.isSingleton = TRUE;
	if(parent){
		EnumChildWindows(parent,WindowEnumProc,(LPARAM)&wi);
	}else{
		EnumWindows(WindowEnumProc,(LPARAM)&wi);
	}

	return wi.hWnd;
}

BOOL
CInjectUtils::getMultipleWindows(LPWNDINFO wi){
	wi->isSingleton = FALSE;
	wi->hWndsSize = 0;
	if(wi->parent){
		EnumChildWindows(wi->parent,WindowEnumProc,(LPARAM)wi);
	}else{
		EnumWindows(WindowEnumProc,(LPARAM)wi);
	}
	return TRUE;
}

BOOL
CInjectUtils::sendMessage(DWORD pid,HWND hWnd,UINT msg,PVOID lpData,DWORD cbData){
	HWND cmdHwnd = hWnd;
	if(!cmdHwnd){
		TCHAR pidStr[20];
		_stprintf_s(pidStr,20,TEXT("LY%d"),pid);
		cmdHwnd = FindWindow(CLSNAME_CMD,pidStr);
		if(!cmdHwnd){
			return FALSE;
		}
	}
	
	COPYDATASTRUCT copyData;
	copyData.dwData = 0;
	copyData.cbData = cbData;
	copyData.lpData = lpData;
	return SendMessage(cmdHwnd, WM_COPYDATA,(WPARAM)msg,(LPARAM)&copyData);
}

BOOL
CInjectUtils::postMessage(DWORD pid,HWND hWnd,UINT msg,PVOID lpData,DWORD cbData){
	HWND cmdHwnd = hWnd;
	if(!cmdHwnd){
		TCHAR pidStr[20];
		_stprintf_s(pidStr,20,TEXT("LY%d"),pid);
		cmdHwnd = FindWindow(CLSNAME_CMD,pidStr);
		if(!cmdHwnd){
			return FALSE;
		}
	}

	COPYDATASTRUCT copyData;
	copyData.dwData = 0;
	copyData.cbData = cbData;
	copyData.lpData = lpData;
	return PostMessage(cmdHwnd, WM_COPYDATA,(WPARAM)msg,(LPARAM)&copyData);
}

BOOL
CInjectUtils::GetRemoteData(DWORD pid,UINT msg,
		__in PVOID inData,
		__in DWORD inCbData,
		__out PVOID lpData,
		__in DWORD cbData){
	TCHAR pidStr[20];
	_stprintf_s(pidStr,20,TEXT("LY%d"),pid);
	HWND cmdHwnd = FindWindow(CLSNAME_CMD,pidStr);
	if(!cmdHwnd){
		return FALSE;
	}
	DWORD size = sizeof(GetData) + inCbData;
	char* data = new char[size];

	PGetData gd = (PGetData)data;
	sprintf_s(gd->lpName,sizeof(gd->lpName),"%x",rand());
	gd->cbData = cbData;

	if(inData&&inCbData){
		LPSTR extrData = (LPSTR)((DWORD)data+sizeof(GetData));
		CopyMemory(extrData,inData,inCbData);
	}
	
	HANDLE hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,gd->cbData,gd->lpName);
	if (hMapFile == NULL){
		delete data;
		return FALSE;
	}

	LPVOID pBuf = MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,gd->cbData);
	if (pBuf == NULL){
		CloseHandle(hMapFile);
		delete data;
		return FALSE;
	}

	ZeroMemory(pBuf,gd->cbData);

	COPYDATASTRUCT copyData;
	copyData.dwData = 0;
	copyData.cbData = size;
	copyData.lpData = data;
	SendMessage(cmdHwnd, WM_COPYDATA,(WPARAM)msg,(LPARAM)&copyData);
	
	CopyMemory(lpData,pBuf,cbData);
	UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);

	delete data;
	return TRUE;
}

BOOL
CInjectUtils::sendStringIme(DWORD processId,LPCWSTR text){
	return sendMessage(processId,0,CMD_SEND_STRING_IME,(PVOID)text,wcslen(text)*sizeof(WCHAR));
}

BOOL 
CInjectUtils::ActiveWindow(HWND hWnd){
    HWND hForeWnd = GetForegroundWindow();
    DWORD dwForeID = GetWindowThreadProcessId(hForeWnd, NULL);
    DWORD dwCurID = GetCurrentThreadId();
    AttachThreadInput(dwCurID, dwForeID, TRUE);
    ShowWindow(hWnd, SW_SHOWNORMAL);
    SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    SetForegroundWindow(hWnd);
    AttachThreadInput(dwCurID, dwForeID, FALSE);
    return TRUE;
}

HKL
CInjectUtils::InstallIme(){
	LPCSTR imeName = IME_NAMEA;
	char moduleName[MAX_PATH];
	GetModuleFileNameA(module,moduleName,MAX_PATH);
	LPCSTR imeFile = moduleName;
	HKL hklList[50];
	int count = GetKeyboardLayoutList(50,hklList);
	if(count==0){
		return 0;
	}

	HKL hkl = 0;
	char keyPath[MAX_PATH] = {0};
	BYTE keyValue[50];
	DWORD keyValueLength = 50;
	HKEY	hKey;
	
	for(int i=0;i<count;i++){
		hkl = hklList[i];
		sprintf_s(keyPath,MAX_PATH,"%s%x",KEYBOARD_LAYOUTSA,hkl);
		if(RegOpenKeyExA(HKEY_LOCAL_MACHINE,keyPath,0,KEY_READ,&hKey)==ERROR_SUCCESS){
			if(RegQueryValueExA(hKey,"Ime File",NULL,NULL,keyValue,&keyValueLength)==ERROR_SUCCESS){
				if(_stricmp(imeName,(LPSTR)keyValue)==0){
					RegCloseKey(hKey);
					return hkl;
				}
			}
			RegCloseKey(hKey);
		}
	}

	char systemPath[MAX_PATH];
	GetSystemDirectoryA(systemPath, MAX_PATH);
	lstrcatA(systemPath,"\\");
	lstrcatA(systemPath,imeName);
	CopyFileA(imeFile,systemPath,false);
	CopyFileA(imeFile,imeName,false);

	hkl = ImmInstallIMEA(imeName,"LYIME");
	return hkl;
}

BOOL
CInjectUtils::UninstallIme(){
	
	HKEY	hKey;
	DWORD dwIndex = 0;
	CHAR   lpName[MAX_PATH];  
	DWORD lpcName = MAX_PATH;
	
	HKL hkl = GetImeByName(IME_NAMEA);
	

	WNDINFO wi = {0};
	wi.dwProcessId = 0;
	wi.className = CLSNAME_CMDA;
	CInjectUtils::getMultipleWindows(&wi);
	DWORD curPid = GetCurrentProcessId();
	for(DWORD i=0;i<wi.hWndsSize;i++){
		DWORD id = (DWORD)GetWindowLongPtr(wi.hWnds[i],LYGWL_PID);
		if(id!=curPid){
			UnloadIme2(id,hkl);
		}
	}

	if(hkl){
		UnloadKeyboardLayout(hkl); 
	}

	if(RegOpenKeyExA(HKEY_LOCAL_MACHINE,KEYBOARD_LAYOUTSA,0,KEY_ALL_ACCESS,&hKey)==ERROR_SUCCESS){
		sprintf_s(lpName,MAX_PATH,"%X",hkl);
		RegDeleteKeyExA(hKey,lpName,KEY_WOW64_32KEY,0);
		RegCloseKey(hKey);
	}
	
	if(hkl){
		if(RegOpenKeyExA(HKEY_CURRENT_USER,PRELOADA,0,KEY_ALL_ACCESS,&hKey)==ERROR_SUCCESS){
			BYTE keyValue[50];
			DWORD keyValueLength = 50;
			dwIndex = 0;
			lpcName = MAX_PATH;
			while(RegEnumValueA(hKey,dwIndex++,lpName,&lpcName,NULL,NULL,keyValue,&keyValueLength)!=ERROR_NO_MORE_ITEMS){
				if(keyValueLength){
					DWORD val = strtoul((LPSTR)keyValue,NULL,16);
					if(val==(DWORD)hkl){
						RegDeleteValueA(hKey,lpName);
					}
				}
				lpcName = MAX_PATH;
			}
			RegCloseKey(hKey);
		}
	}
		
	char systemPath[MAX_PATH];
	char imePath[MAX_PATH];
	GetSystemDirectoryA(systemPath, MAX_PATH);
	lstrcpyA(imePath,systemPath);
	lstrcatA(imePath,"\\");
	lstrcatA(imePath,IME_NAMEA);
	
	Sleep(1000);
	
	DeleteFileA(imePath);
	DeleteFileA(INI_PATHA);
	
	return TRUE;
}

BOOL
CInjectUtils::UnloadIme(DWORD pid,HKL hkl){
	if(!pid){
		return FALSE;
	}
	CHAR moduleName[MAX_PATH];
	CHAR unModuleName[MAX_PATH];
	CHAR dirPath[MAX_PATH];
	
	GetCurrentDirectoryA(MAX_PATH,dirPath);
	GetModuleFileNameA(module,moduleName,MAX_PATH);
	sprintf_s(unModuleName,MAX_PATH,"%s\\ly%x.dll",dirPath,rand());
	LPSTR pModName = PathFindFileNameA(unModuleName);

	CopyFileA(moduleName,unModuleName,false);

	HMODULE hModule = CInjectUtils::LoadDll(pid,unModuleName);
	
	WNDINFO wi = {0};
	wi.dwProcessId = pid;
	wi.className = CLSNAME_CMDA;
	CInjectUtils::getMultipleWindows(&wi);

	HWND hwnd = 0;
	for(DWORD i=0;i<wi.hWndsSize;i++){
		hwnd = wi.hWnds[i];
		HMODULE h = (HMODULE)GetWindowLongPtr(hwnd,LYGWL_MODULE);
		if(h==hModule){
			break;
		}
	}

	if(!hwnd){
		sendMessage(pid,hwnd,CMD_FREE_SELF,0,0);
		Sleep(1000);
		DeleteFileA(unModuleName);
		return FALSE;
	}

	DllInfo di;
	ZeroMemory(&di,sizeof(DllInfo));
	lstrcpyA(di.dllname,pModName);
	lstrcpyA(di.method,"ImmFreeLayout");
	di.cbParamNum = 1;
	di.cbParamSize = sizeof(HKL);

	DWORD diSize = sizeof(DllInfo);
	DWORD dataSize = diSize+di.cbParamSize;
	char* data = new char[dataSize];
	CopyMemory(data,&di,diSize);
	CopyMemory(data+diSize,&hkl,di.cbParamSize);
	sendMessage(pid,hwnd,CMD_INVOKE_DLL_METHOD,data,dataSize);
	
	sendMessage(pid,hwnd,CMD_FREE_SELF,0,0);
	Sleep(1000);
	delete data;
	DeleteFileA(unModuleName);

	return TRUE;
}

BOOL
CInjectUtils::UnloadIme2(DWORD pid,HKL hkl){
	if(!pid){
		return FALSE;
	}
	return sendMessage(pid,0,CMD_FREE_IME,&hkl,4);
}

HMODULE
CInjectUtils::LoadDll(DWORD pid,LPCSTR dllname,LPCSTR method){
	HWND cmdHwnd = CInjectUtils::getSingletonWindow(pid,0,CLSNAME_CMDA,FALSE);
	if(!cmdHwnd){
		return 0;
	}
	if(!dllname){
		return 0;
	}
	DWORD size = sizeof(DllInfo) + sizeof(GetData);
	char* data = new char[size];


	PDllInfo di = (PDllInfo)data;
	strcpy_s(di->dllname,MAX_PATH,dllname);
	if(method){
		strcpy_s(di->method,MAX_PATH,method);
	}

	PGetData gd = (PGetData)((DWORD)data + sizeof(DllInfo));
	sprintf_s(gd->lpName,sizeof(gd->lpName),"%x",rand());
	gd->cbData = 4;

	HANDLE hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,gd->cbData,gd->lpName);
	if (hMapFile == NULL){
		delete data;
		return FALSE;
	}

	LPVOID pBuf = MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,gd->cbData);
	if (pBuf == NULL){
		CloseHandle(hMapFile);
		delete data;
		return FALSE;
	}
	ZeroMemory(pBuf,gd->cbData);

	sendMessage(pid,0,CMD_LOAD_DLL,data,size);

	DWORD hModule = *(PDWORD)pBuf;
	UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
	delete data;

	return (HMODULE)hModule;	 
}

BOOL
CInjectUtils::FreeDll(DWORD pid,LPCSTR dllname){
	DllInfo idf;
	strcpy_s(idf.dllname,MAX_PATH,dllname);
	return sendMessage(pid,0,CMD_FREE_DLL,&idf,sizeof(DllInfo));
}

HKL
CInjectUtils::GetImeByName(LPCSTR imeName){
	HKEY	hKey,subKey;
	DWORD dwIndex = 0;
	char   lpName[MAX_PATH];  
	DWORD lpcName = MAX_PATH;
	BYTE keyValue[50];
	DWORD keyValueLength = 50;

	HKL hkl = 0;

	if(RegOpenKeyExA(HKEY_LOCAL_MACHINE,KEYBOARD_LAYOUTSA,0,KEY_READ,&hKey)==ERROR_SUCCESS){
		while(RegEnumKeyExA(hKey,dwIndex++,lpName,&lpcName,NULL,NULL,NULL,NULL)!=ERROR_NO_MORE_ITEMS){
			if(RegOpenKeyExA(hKey,lpName,0,KEY_READ,&subKey)==ERROR_SUCCESS){
				if(RegQueryValueExA(subKey,"Ime File",NULL,NULL,keyValue,&keyValueLength)==ERROR_SUCCESS){
					if(_stricmp(imeName,(LPSTR)keyValue)==0){
						hkl = (HKL)strtoul(lpName,NULL,16);
						RegCloseKey(subKey);
						break;
					}
				}
				RegCloseKey(subKey);
			}
			lpcName = MAX_PATH;
		}
		RegCloseKey(hKey);
	}

	return hkl;
}

BOOL
CInjectUtils::InvokeDllMethod(DWORD pid,LPCSTR dllName,LPCSTR method,DWORD paramNum,LPVOID param,DWORD paramSize){
	HWND cmdHwnd = CInjectUtils::getSingletonWindow(pid,0,CLSNAME_CMDA,FALSE);
	if(!cmdHwnd){
		return FALSE;
	}
	DllInfo di;
	ZeroMemory(&di,sizeof(DllInfo));
	lstrcpyA(di.dllname,dllName);
	lstrcpyA(di.method,method);
	di.cbParamNum = paramNum;
	di.cbParamSize = paramSize;

	DWORD diSize = sizeof(DllInfo);
	if(paramNum){
		DWORD dataSize = diSize + di.cbParamSize;
		char* data = new char[dataSize];
		CopyMemory(data,&di,diSize);
		CopyMemory(data+diSize,param,paramSize);
		sendMessage(pid,0,CMD_INVOKE_DLL_METHOD,data,dataSize);
		delete data;
	}else{
		sendMessage(pid,0,CMD_INVOKE_DLL_METHOD,&di,diSize);
	}
	return TRUE;
}

HMODULE
CInjectUtils::GetModule(DWORD pid,LPSTR moduleName){
	DWORD len = strlen(moduleName) + 1;
	DWORD handle = 0;
	CInjectUtils::GetRemoteData(pid,CMD_GET_MODULE_HANDLE,moduleName,len,&handle,4);
	return (HMODULE)handle;
}